/*
 * Project: Bearing
 * Copyright (C) 2009 ralfoide gmail com,
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.alfray.bearing.pub.ui;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.util.AttributeSet;
import android.view.View;

//-----------------------------------------------

public class CompassView extends View {

    private int mCenterX;
    private int mCenterY;
    private int mRadius;
    private Paint mLinePaint;
    private float mNorthAngleDeg;
    private float mPointerAngleDeg;
    private Paint mLetterPaint;
    private Paint mPointerPaint;
    private Path mPointerPath;
    private Paint mLinePaint2;

    /**
     * Simple constructor to use when creating a view from code.
     *
     * @see View#View(Context)
     */
    public CompassView(Context context) {
        this(context, null);
    }

    /**
     * Constructor that is called when inflating a view from XML.
     *
     * @see View#View(Context, AttributeSet)
     */
    public CompassView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * Perform inflation from XML and apply a class-specific base style.
     *
     * @see View#View(Context, AttributeSet, int)
     */
    public CompassView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        // TODO Add constructor-time code here.
    }

    /** Changes the North degree angle and invalidate view to redraw it. */
    public void setNorthAngleDeg(float angleDeg) {
        mNorthAngleDeg = angleDeg;
        invalidate();
    }

    /** Changes the Pointer degree angle and invalidates the view to redraw it. */
    public void setPointerAngleDeg(float pointerAngleDeg) {
        mPointerAngleDeg = pointerAngleDeg;
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // If widthMeasureSpec is of type UNSPECIFIED, uses the minimum width,
        // If mode is AT_MOST or EXACTLY, uses the size encoded in widthMeasureSpec.
        int width = View.getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        int height = View.getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);

        // Use the smaller of the two to make it square
        if (height < width) width = height;

        setMeasuredDimension(width, width);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        // View size has changed. Recreate static content.
        // Called first with oldw/h=0.
        mCenterX = w / 2;
        mCenterY = h / 2;
        mRadius = Math.min(mCenterX, mCenterY);

        mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mLinePaint.setStyle(Style.STROKE);
        mLinePaint.setColor(0xFFFF9900);
        mLinePaint.setStrokeWidth(2);

        mLinePaint2 = new Paint(mLinePaint);
        mLinePaint2.setPathEffect(new DashPathEffect(new float[] { 3, 9 }, 0));

        mLetterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mLetterPaint.setTextAlign(Align.CENTER);
        mLetterPaint.setColor(0xFFFFFFFF);

        FontMetrics fm = mLetterPaint.getFontMetrics();
        float a = - fm.top;
        float a2 = a/2;
        float d = fm.bottom;
        float r = mRadius - d - a - 10 - 5;
        Path p = mPointerPath = new Path();
        p.moveTo(   0, -a2);
        p.cubicTo(/*control1*/ a2, -a2, /*control2*/ a2, 0, /*to*/ a2, 0);
        p.lineTo(   a, r - 2*a);
        p.lineTo( 2*a, r - 2*a);
        p.lineTo(   0, r);
        p.lineTo(-2*a, r - 2*a);
        p.lineTo(  -a, r - 2*a);
        p.lineTo( -a2, 0);
        p.cubicTo(/*control1*/ -a2, 0, /*control2*/ -a2, -a2, /*to*/ 0, -a2);

        mPointerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPointerPaint.setStyle(Style.FILL);
        mPointerPaint.setColor(0xFFFF0000);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (mLetterPaint == null) return;

        canvas.translate(mCenterX, mCenterY);
        canvas.rotate(mNorthAngleDeg);

        // Draw outer circle, NSWE letters and a few ticks

        FontMetrics fm = mLetterPaint.getFontMetrics();
        float a = - fm.top;
        float d = fm.bottom;
        float r = mRadius - d - a - 10;
        canvas.drawCircle(0, 0, r, mLinePaint);
        canvas.drawLine(0, -r, 0, +r, mLinePaint);
        canvas.drawLine(-r, 0, +r, 0, mLinePaint);

        canvas.rotate(45);
        canvas.drawLine(0, -r, 0, +r, mLinePaint2);
        canvas.rotate(90);
        canvas.drawLine(0, -r, 0, +r, mLinePaint2);
        canvas.rotate(-90-45);

        float yt = -r -d - 5;
        canvas.drawText("N", 0, yt, mLetterPaint);
        canvas.rotate(90);
        canvas.drawText("E", 0, yt, mLetterPaint);
        canvas.rotate(90);
        canvas.drawText("S", 0, yt, mLetterPaint);
        canvas.rotate(90);
        canvas.drawText("W", 0, yt, mLetterPaint);
        canvas.rotate(90);

        float r2 = r - a;
        for (float inc = 90/4.f, deg = 0; deg < 360; deg += inc) {
            canvas.drawLine(0, r, 0, r2, mLinePaint);
            canvas.rotate(inc);
        }

        canvas.rotate(180 + mPointerAngleDeg);
        canvas.drawPath(mPointerPath, mPointerPaint);

        canvas.drawCircle(0, 0, 1, mLinePaint);
    }
}